package yxgf.oem.oemquotemgt.mservice.service.impl;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.nacos.common.utils.StringUtils;
import kd.bos.coderule.api.CodeRuleInfo;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.metadata.IDataEntityType;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.openapi.common.result.CustomApiResult;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
import kd.bos.servicehelper.coderule.CodeRuleServiceHelper;
import org.springframework.stereotype.Service;
import yxgf.oem.oemquotemgt.commons.dto.*;
import yxgf.oem.oemquotemgt.commons.enums.ContractQuoteModeEnum;
import yxgf.oem.oemquotemgt.commons.enums.QuoteModeEnum;
import yxgf.oem.oemquotemgt.commons.enums.QuoteTypeEnum;
import yxgf.oem.oemquotemgt.commons.utils.DateUtils;
import yxgf.oem.oemquotemgt.mservice.service.IContractAppointService;

import java.time.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @description： 合同约定服务服务
 * @version: v1.0
 * @author: Junit
 * @date: 2025/5/14
 */
@Service
public class ContractAppointServiceImpl implements IContractAppointService {
    private static final Log logger = LogFactory.getLog(ContractAppointServiceImpl.class);

    /**
     * 日志消息
     */
    public static final String LOG_PREFIX = "合同约定单定时生成定价单定时任务-";

    @Override
    public CustomApiResult<Boolean> genQuoteBill() {
        LocalDate today = LocalDate.now();
        int dayOfMonth = today.getDayOfMonth();
        int currYear = today.getYear();
        int currMonth = today.getMonthValue();

        /**
         * 一、获取已审核合同信息
         */
        QFilter qFilter1 = new QFilter("billstatus", QCP.equals, "C");
        // QFilter qFilter2 = new QFilter("yxgf_start_date", QCP.less_equals, today);
        // QFilter qFilter3 = new QFilter("yxgf_end_date", QCP.large_equals, today);
        QFilter qFilter4 = new QFilter("yxgf_entryentity_qperiod.yxgf_qdate", QCP.equals, dayOfMonth);
        // QFilter filter = qFilter1.and(qFilter2).and(qFilter3).and(qFilter4);

        DynamicObjectCollection contractBill = QueryServiceHelper.query("yxgf_contract_bill",
                "id,billno,yxgf_saleorg,yxgf_customer," +
                        "yxgf_quote_mode,yxgf_advanced_days,yxgf_principal,yxgf_order_addr," +
                        "yxgf_stock_addr,yxgf_reserved_addr," +
                        "yxgf_start_date,yxgf_end_date," +
                        "yxgf_base_days,yxgf_quote_days,yxgf_range,yxgf_base_x," +
                        "yxgf_entryentity_qperiod.yxgf_qdate as quote_date",
                qFilter1.toArray());

        List<ContractBaseInfoDto> contractOriList = new ArrayList<>();
        for (DynamicObject dyn : contractBill) {
            // 基本信息
            ContractBaseInfoDto baseInfoDto = new ContractBaseInfoDto();
            String billNo = dyn.getString("billno");
            // 编号
            baseInfoDto.setBillNo(billNo);
            // 客户
            baseInfoDto.setCusId(dyn.getLong("yxgf_customer"));
            // 提前生成日
            baseInfoDto.setAdvancedDay(dyn.getInt("yxgf_advanced_days"));
            // 报价日
            List<Integer> qDays = new ArrayList<>();
            qDays.add(dyn.getInt("quote_date"));
            baseInfoDto.setQuoteDays(qDays);
            /*
             * 报价模式
             * -原料价格：产品，隐藏【报价规则】、【基数计算方式】、【汇易网价格明细】
             * -汇易网价格：产品，【报价规则】、【基数计算方式】、【汇易网价格明细】
             */
            Long billId = dyn.getLong("id");
            baseInfoDto.setQuoteMode(dyn.getString("yxgf_quote_mode"));
            if (!StringUtils.equals(baseInfoDto.getQuoteMode(), ContractQuoteModeEnum.MAT_PRICE.getCode())) {
                // 1、报价规则
                ContractQuoteRuleDto quoteRuleDto = new ContractQuoteRuleDto();
                quoteRuleDto.setBaseXDays(dyn.getInt("yxgf_base_days"));
                quoteRuleDto.setQuoteDays(dyn.getInt("yxgf_quote_days"));
                quoteRuleDto.setRange(dyn.getBigDecimal("yxgf_range"));
                quoteRuleDto.setBaseX(dyn.getBigDecimal("yxgf_base_x"));
                baseInfoDto.setContractQuoteRuleDto(quoteRuleDto);

                // 2、基数计算方式
                List<ContractBaseWayDto> baseWayList = new ArrayList<>();
                DynamicObject baseWayBill = BusinessDataServiceHelper.loadSingle(billId, "yxgf_contract_bill");
                DynamicObjectCollection proEntity = baseWayBill.getDynamicObjectCollection("yxgf_entryentity_pro");
                for (DynamicObject bc : proEntity) {
                    ContractBaseWayDto tem = new ContractBaseWayDto();
                    tem.setMatId(bc.getLong("yxgf_mat_code"));
                    tem.setSourceAddr(bc.getString("yxgf_addr"));
                    tem.setSourceChanId(bc.getLong("yxgf_source"));
                    tem.setWeight(bc.getBigDecimal("yxgf_weight"));
                    tem.setAvgPrice(bc.getBigDecimal("yxgf_avg_price"));
                    baseWayList.add(tem);
                }

                // 3、汇易网价格
                List<ContractHywPriceDto> hywPriceList = new ArrayList<>();
                DynamicObject hywPriceBill = BusinessDataServiceHelper.loadSingle(billId, "yxgf_contract_bill");
                DynamicObjectCollection hywEntity = hywPriceBill.getDynamicObjectCollection("yxgf_subentryentity_hyw");
                for (DynamicObject bc : hywEntity) {
                    ContractHywPriceDto tem = new ContractHywPriceDto();
                    tem.setMatId(bc.getLong("yxgf_mat_code"));
                    tem.setDate(bc.getDate("yxgf_date"));
                    tem.setHywPrice(bc.getBigDecimal("yxgf_hyw_price"));
                    hywPriceList.add(tem);
                }
            }

            // 获取产品
            List<ContractProductDto> productDtoList = new ArrayList<>();
            DynamicObject bill = BusinessDataServiceHelper.loadSingle(billId, "yxgf_contract_bill");
            DynamicObjectCollection proEntity = bill.getDynamicObjectCollection("yxgf_entryentity_pro");
            for (DynamicObject pro : proEntity) {
                ContractProductDto tem = new ContractProductDto();
                tem.setProId(pro.getLong("yxgf_pro_code"));
                tem.setMount(pro.getBigDecimal("yxgf_pro_amount"));
            }
            baseInfoDto.setProductDtoList(productDtoList);

            contractOriList.add(baseInfoDto);
        }

        /**
         * 二、获取报价合同
         */
        List<ContractBaseInfoDto> list = contractOriList.stream()
                .filter(distinctByKey(ContractBaseInfoDto::getBillNo))
                .collect(Collectors.toList());

        /**
         * 三、获取报价日合同
         */
        List<ContractBaseInfoDto> dataList = new ArrayList<>();
        for (ContractBaseInfoDto tem : list) {
            // 查找相同合同
            List<ContractBaseInfoDto> sameConBill = findContractsByBillNo(contractOriList, tem.getBillNo());
            for (ContractBaseInfoDto sameCon : sameConBill) {
                // 1、预测日
                int advancedDays = sameCon.getAdvancedDay();
                if (advancedDays < 1 || advancedDays > 31) {
                    logger.info(LOG_PREFIX + "生成报价单失败，获取提前生成定价单天数无效，值为:" + advancedDays);
                    continue;
                }

                // 2、生成完整报价日，确保报价日期存在
                if (sameCon.getQuoteDays().size() == 0 && sameCon.getQuoteDays().get(0) < 0 || sameCon.getQuoteDays().get(0) > 31) {
                    logger.info(LOG_PREFIX + "生成报价单失败，当前报价日期无效");
                    continue;
                }
                LocalDate quoteDay;
                try {
                    quoteDay = LocalDate.of(currYear, currMonth, sameCon.getQuoteDays().get(0));
                } catch (DateTimeException e) {
                    continue;
                }

                // 3、生成报价日期
                LocalDate quoteDate = quoteDay.minusDays(advancedDays);


                // 4、判断是否是报价当天，生成定价单
                boolean result = DateUtils.isBetween(quoteDate,
                        DateUtils.convertLocalDate(sameCon.getContractStarDay()),
                        DateUtils.convertLocalDate(sameCon.getContractEndDay()));

                // 调度任务日期满足生成定价单日期且在合同有效期内
                if (result && !today.equals(quoteDate)) {   // 测试
                    dataList.add(sameCon);
//                    /**
//                     * 1、获取定价单信息
//                     */
//                    QFilter qFilter2 = new QFilter("billno", QCP.equals, sameCon.getBillNo());             // 定价单编号
//                    QFilter qFilter3 = new QFilter("billstatus", QCP.equals, "C");                   // 已审批
//                    QFilter filter4 = qFilter2.and(qFilter3);
//                    DynamicObject quoteBill = QueryServiceHelper.queryOne("yxgf_recipe_pricing",
//                            "id,billno," +
//                                    "yxgf_combofield,yxgf_bjlx," +
//                                    "yxgf_start_qdatetime,yxgf_qend_datetime",
//                            filter4.toArray());
//
//                    /**
//                     * 存在：根据合同查找最新的一条定价单 -- 售前报价
//                     * 不存在：生成新定价单--合同报价
//                     * 2、检查是否生成定价单，生成则不再生成，否则生成单价单
//                     * -是否是在合同有效日内
//                     * -修改报价单报价类型
//                     */
//
//                    // 合同日期，加入生成单价单集
//                    if (quoteBill == null && result) {
//
//                    }
                }
            }

        }

        // 批量生成定价单
        genQBillEntity(dataList, today);
        return CustomApiResult.success(true);
    }


    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 查找日期
     *
     * @param conBills
     * @param billNo
     * @return
     */
    public static List<ContractBaseInfoDto> findContractsByBillNo(List<ContractBaseInfoDto> conBills, String billNo) {
        return conBills.stream()
                .filter(order -> order.getBillNo().equals(billNo))
                .collect(Collectors.toList());
    }

    /**
     * 批量生成定价单
     *
     * @param contractInfos
     * @param today
     */
    private void genQBillEntity(List<ContractBaseInfoDto> contractInfos, LocalDate today) {
        ArrayList<DynamicObject> dynObjects = new ArrayList<>();
        for (ContractBaseInfoDto baseInfoDto : contractInfos) {
            // 获取单据单信息
            DynamicObject quoteBill = getQuoteBillByNo(baseInfoDto.getBillNo());
            boolean existBill = quoteBill == null ? false : true;
            // 合同基本信息
            DynamicObject contractEntity = genContractInfo(baseInfoDto, quoteBill, today, existBill);

            // 报价模式

            // 合同产品
            dynObjects.add(contractEntity);

        }

        DynamicObject[] dynArr = dynObjects.stream().toArray(DynamicObject[]::new);
        // OperationServiceHelper.executeOperate("save", "yxgf_recipe_pricing", dynArr, OperateOption.create());
        // logger.info(LOG_PREFIX + "合同编号【" + contractInfo.getBillNo() + "】生成定价单成功");
    }


    /**
     * 根据合同相关信息封装定价单数据
     * f-新增合同报价,t-售前报价
     *
     * @param baseInfoDto
     * @param sourceBill
     * @param today
     * @param exist
     * @return
     */
    private DynamicObject genContractInfo(ContractBaseInfoDto baseInfoDto, DynamicObject sourceBill, LocalDate today, boolean exist) {
        DynamicObject contractEntity = BusinessDataServiceHelper.newDynamicObject("yxgf_recipe_pricing");
        IDataEntityType dataType = contractEntity.getDataEntityType();
        String ruleName = dataType.getName();
        CodeRuleInfo codeRule = CodeRuleServiceHelper.getCodeRule(ruleName, contractEntity, null);
        String billNo = CodeRuleServiceHelper.getNumber(codeRule, contractEntity);

        /**
         * 一、基本信息
         *  存在定价单时，更新定价单
         *  1、根据报价模式更新：a产品;b报价规则、基数计算方式、汇易网价格
         */
        if (exist) {
            contractEntity.set("billno", sourceBill.getString("billno"));
        } else {
            contractEntity.set("billno", billNo);
        }

        // 单据状态暂存
        contractEntity.set("billstatus", "A");
        // 客户ID
        contractEntity.set("yxgf_customerfield", baseInfoDto.getCusId());

        /**
         * 二、报价信息
         */
        contractEntity.set("yxgf_combofield", QuoteTypeEnum.QUOTE_MODE_CON_SALE);               // 报价类型-合同报价
        contractEntity.set("yxgf_bjlx", QuoteModeEnum.QUOTE_TYPE_MAT);                          // 报价模式三种

        /**
         * 三、合同约定
         */
        contractEntity.set("yxgf_contractld", baseInfoDto.getBillNo());                        // 合同编号
        contractEntity.set("yxgf_start_qdatetime", baseInfoDto.getContractStarDay());          // 开始日期
        contractEntity.set("yxgf_qend_datetime", baseInfoDto.getContractEndDay());             // 结束日期
        contractEntity.set("yxgf_principal", baseInfoDto.getPrincipalId());                    // 负责人

        /**
         * 报价模式：【原料、汇易网】
         */
        if (!StringUtils.equals(baseInfoDto.getQuoteMode(), ContractQuoteModeEnum.MAT_PRICE.getCode())) {
            /*
             * 报价规则
             */
            ContractQuoteRuleDto conRule = baseInfoDto.getContractQuoteRuleDto();
            ZonedDateTime zonedDateTime = today.atStartOfDay(ZoneId.systemDefault());
            Date date = Date.from(zonedDateTime.toInstant());
            contractEntity.set("yxgf_contrat_base_date", date);                                 // 合同基数计算日期
            contractEntity.set("yxgf_base_days", conRule.getBaseXDays());                       // 合同基数计算天数
            contractEntity.set("yxgf_amountfield3", conRule.getBaseX());                        // 合同基数
            contractEntity.set("yxgf_range", conRule.getRange());                               // 约定波动范围

            /*
             * 基数计算方式
             */
            DynamicObjectCollection baseX = contractEntity.getDynamicObjectCollection("base_compute");
            genBaseXInfo(baseX, baseInfoDto.getBaseWayDtoList());

            /*
             * 汇易网价格明细
             */
            DynamicObjectCollection hywPrice = contractEntity.getDynamicObjectCollection("yxgf_subentryentity_hyw");
            gentHywPriceInfo(hywPrice, baseInfoDto.getHywPriceDtoList());
        }

        /**
         * 四、产品 【yxgf_entryentity_pro/yxgf_pro_code、yxgf_pro_amount】
         */
        DynamicObjectCollection pro = contractEntity.getDynamicObjectCollection("yxgf_entryentity");
        genProInfo(pro, baseInfoDto.getProductDtoList());

        return contractEntity;

    }

    /**
     * 获取历史定价单相关信息
     *
     * @param contractNo
     * @return
     */
    private DynamicObject getQuoteBillByNo(String contractNo) {
        QFilter qFilter1 = new QFilter("billno", QCP.equals, contractNo);
        QFilter qFilter2 = new QFilter("billstatus", QCP.equals, "C");
        QFilter filter = qFilter1.and(qFilter2);
        DynamicObjectCollection comObjCollection = QueryServiceHelper.query("yxgf_recipe_pricing",
                "id,billno," +
                        "yxgf_combofield,yxgf_bjlx," +
                        "yxgf_start_qdatetime,yxgf_qend_datetime,createtime",
                filter.toArray(), "createtime desc");
        if (comObjCollection.size() > 0) {
            return comObjCollection.get(0);
        }
        return null;
    }

    /**
     * 生成产品
     *
     * @param dynObjCollect
     * @param productDtoList
     */
    private void genProInfo(DynamicObjectCollection dynObjCollect, List<ContractProductDto> productDtoList) {
        IntStream.range(0, productDtoList.size())
                .mapToObj(index -> genProObject(productDtoList.get(index), dynObjCollect.getDynamicObjectType()))
                .forEach(dynObjCollect::add);
    }

    private DynamicObject genProObject(ContractProductDto proDto, DynamicObjectType type) {
        DynamicObject detail = new DynamicObject(type);
        // otc产品编码
        detail.set("yxgf_basedatafield2", proDto.getProId());
        // 金额
        detail.set("yxgf_pro_amount", proDto.getMount());
        return detail;
    }


    /**
     * 生成基数计算方式
     *
     * @param dynObjCollect
     * @param wayList
     */
    private void genBaseXInfo(DynamicObjectCollection dynObjCollect,
                              List<ContractBaseWayDto> wayList) {
        IntStream.range(0, wayList.size())
                .mapToObj(index -> genWayObject(wayList.get(index), dynObjCollect.getDynamicObjectType()))
                .forEach(dynObjCollect::add);
    }

    private DynamicObject genWayObject(ContractBaseWayDto proDto, DynamicObjectType type) {
        DynamicObject baseXObj = new DynamicObject(type);
        // 编码
        baseXObj.set("yxgf_material_code", proDto.getMatId());
        // 产地
        baseXObj.set("yxgf_addr", proDto.getSourceAddr());
        // 权值
        baseXObj.set("yxgf_weight", proDto.getWeight());
        // 均价
        baseXObj.set("yxgf_avg_price", proDto.getAvgPrice());
        return baseXObj;
    }


    /**
     * 汇易网价格明细
     *
     * @param dynObjCollect
     * @param hywPriceList
     */
    private void gentHywPriceInfo(DynamicObjectCollection dynObjCollect, List<ContractHywPriceDto> hywPriceList) {
        IntStream.range(0, hywPriceList.size())
                .mapToObj(index -> genHywData(hywPriceList.get(index), dynObjCollect.getDynamicObjectType()))
                .forEach(dynObjCollect::add);
    }

    private DynamicObject genHywData(ContractHywPriceDto hywDto, DynamicObjectType type) {
        DynamicObject hywObj = new DynamicObject(type);
        // 原料编码
        hywObj.set("yxgf_mat_code", hywDto.getMatId());
        // 日期
        hywObj.set("yxgf_date", hywDto.getDate());
        // 渠道价格
        hywObj.set("yxgf_hyw_price", hywDto.getDate());
        return hywObj;
    }
}
